import threading
import time
import serial
from log_manager import LogManager
from protocol_parser import ProtocolParser

class SerialProtocol:
    def __init__(self, port, baudrate=2000000):
        """初始化串口协议
        
        Args:
            port: 串口名称
            baudrate: 波特率
        """
        self.port = port
        self.baudrate = baudrate
        self.serial = None
        self.parser = ProtocolParser()
        self.running = False
        self.callbacks = {}
        self.response_events = {}
        self.response_data = {}
        self.data_buffer = bytearray()
        self._lock = threading.Lock()
        
        self._connect()
        
    def _connect(self):
        """连接串口"""
        try:
            self.serial = serial.Serial(
                port=self.port,
                baudrate=self.baudrate,
                timeout=0.1  # 设置读超时
            )
            LogManager.info(f"串口 {self.port} 已打开")
            
            # 启动接收线程
            self._start_receive()
            
        except Exception as e:
            LogManager.error(f"打开串口失败: {str(e)}")
            raise
            
    def _start_receive(self):
        """启动接收线程"""
        self.running = True
        self.receive_thread = threading.Thread(target=self._receive_task)
        self.receive_thread.daemon = True
        self.receive_thread.start()
        
    def _receive_task(self):
        """接收任务"""
        try:
            while self.running:
                try:
                    # 读取数据
                    if self.serial and self.serial.is_open:
                        data = self.serial.read(1024)  # 一次最多读取1024字节
                        if data:
                            # 打印原始数据
                            hex_data = ' '.join([f'{b:02X}' for b in data])
                            # LogManager.debug(f"接收数据: {hex_data}")
                            
                            # 解析数据
                            for byte in data:
                                result = self.parser.parse_byte(byte)
                                if result:
                                    cmd, payload = result
                                    LogManager.debug(f"解析到命令: 0x{cmd:02X}, 数据长度: {len(payload)}")
                                    self._handle_response(cmd, payload)
                                # 打印parser状态
                                # LogManager.debug(f"parser状态: {self.parser.state}")    
                                    
                except serial.SerialException as e:
                    LogManager.error(f"串口读取错误: {str(e)}")
                    break
                    
        except Exception as e:
            LogManager.error(f"接收任务异常: {str(e)}")
        finally:
            LogManager.info("接收任务结束")
            
    def _handle_response(self, cmd, payload):
        """处理响应数据
        
        Args:
            cmd: 命令字
            payload: 数据负载
        """
        try:
            # LogManager.debug(f"处理响应: cmd=0x{cmd:02X}, payload={' '.join([f'{b:02X}' for b in payload])}")
            
            with self._lock:
                # 如果有等待此命令的事件，设置响应数据并触发事件
                if cmd in self.response_events:
                    self.response_data[cmd] = payload
                    self.response_events[cmd].set()
                    LogManager.debug(f"已设置响应数据: cmd=0x{cmd:02X}")
                else:
                    LogManager.debug(f"没有等待此命令的事件: cmd=0x{cmd:02X}")
                    
                # 如果有此命令的回调函数，调用回调
                if cmd in self.callbacks:
                    try:
                        self.callbacks[cmd](payload)
                    except Exception as e:
                        LogManager.error(f"回调函数异常: {str(e)}")
                        
        except Exception as e:
            LogManager.error(f"处理响应数据失败: {str(e)}")

    def register_callback(self, cmd, callback):
        """注册命令回调函数
        
        Args:
            cmd: 命令字
            callback: 回调函数，接收payload参数
        """
        self.callbacks[cmd] = callback
        
    def send_command(self, cmd, data=None):
        """发送命令
        
        Args:
            cmd: 命令字
            data: 数据负载
            
        Returns:
            bool: 是否成功
        """
        try:
            # 打包数据
            packet = self.parser.pack(cmd, data)
            
            # 打印发送的数据
            hex_data = ' '.join([f'{b:02X}' for b in packet])
            LogManager.debug(f"发送数据长度: {len(packet)}")
            
            # 发送数据
            if self.serial and self.serial.is_open:
                self.serial.write(packet)
                LogManager.debug(f"发送命令 0x{cmd:02X} 成功")
                return True
                
            return False
            
        except Exception as e:
            LogManager.error(f"发送命令失败: {str(e)}")
            return False
            
    def wait_response(self, cmd, timeout=5.0):
        """等待命令响应
        
        Args:
            cmd: 命令字
            timeout: 超时时间(秒)
            
        Returns:
            bool: 是否收到响应
        """
        try:
            # 创建事件
            event = threading.Event()
            
            # 注册事件
            with self._lock:
                self.response_events[cmd] = event
                LogManager.debug(f"注册等待事件: cmd=0x{cmd:02X}")
            
            # 等待事件
            if event.wait(timeout):
                LogManager.debug(f"收到响应: cmd=0x{cmd:02X}")
                return True
            else:
                LogManager.warning(f"等待命令 0x{cmd:02X} 响应超时")
                return False
                
        except Exception as e:
            LogManager.error(f"等待响应失败: {str(e)}")
            return False
            
        finally:
            # 清理事件
            with self._lock:
                self.response_events.pop(cmd, None)
                LogManager.debug(f"清理等待事件: cmd=0x{cmd:02X}")

    def wait_response_data(self, cmd, timeout=5.0):
        """等待命令响应数据
        
        Args:
            cmd: 命令字
            timeout: 超时时间(秒)
            
        Returns:
            bytes: 响应数据，超时返回None
        """
        try:
            if self.wait_response(cmd, timeout):
                with self._lock:
                    data = self.response_data.pop(cmd, None)
                    # LogManager.debug(f"获取响应数据: cmd=0x{cmd:02X}, data={' '.join([f'{b:02X}' for b in data])} if data else 'None'")
                    if cmd == 0x08:
                        LogManager.debug(f"获取响应数据: cmd=0x{cmd:02X}, 数据={data}")
                    else:
                        LogManager.debug(f"获取响应数据: cmd=0x{cmd:02X}, 数据长度={len(data)}")    
                    return data
            return None
            
        except Exception as e:
            LogManager.error(f"获取响应数据失败: {str(e)}")
            return None
        
    def close(self):
        """关闭串口"""
        self.running = False
        if self.serial:
            self.serial.close()
            LogManager.info(f"串口 {self.port} 已关闭")
            
    def is_open(self):
        """检查串口是否打开
        
        Returns:
            bool: 串口是否打开
        """
        return self.serial is not None and self.serial.is_open
